using GameFrameWork;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;

namespace GameFrameWork
{

    [DisallowMultipleComponent]
    public class UIRoundCornerRectMesh : UIBaseMesh
    {
        [SerializeField] float radiusValue = 20;
        [SerializeField] int segmentValue = 20;
        [SerializeField] int cornerTag = 15;
        [SerializeField] ERoundCornerDirection _direction = ERoundCornerDirection.Outer;

        public float Radius { get { return radiusValue; } set { radiusValue = value; SetVertexDirty(); } }
        public int Segment { get { return segmentValue; } set { segmentValue = value; SetVertexDirty(); } }


        void SetVertexDirty()
        {
            graphic?.SetVerticesDirty();
        }

        float GetDefaultRadius()
        {
            float width = transform.GetComponent<RectTransform>().rect.width;
            float height = transform.GetComponent<RectTransform>().rect.height;
            return Mathf.Min(width, height) * 0.5f;
        }

        private float DeltaAngleEquation(int index)
        {
            switch (_direction)
            {
                case ERoundCornerDirection.Inner:
                    return (-index) * 0.5f * Mathf.PI;
                case ERoundCornerDirection.Outer:
                    return (3 - index) * 0.5f * Mathf.PI;
            }
            return 0;
        }

        float delta_vec_w;
        float delta_vec_h;
        float delta_uv_w;
        float delta_uv_h;

        Vector2[] bound4 = new Vector2[4];



        protected override void OnModifyMesh(VertexHelper toFill, ref Vector4 outBound, ref Vector4 outUV, ref Color outColor)
        {
            base.OnModifyMesh(toFill, ref outBound, ref outUV, ref outColor);

            if (radiusValue <= 0) return;
            toFill.Clear();

            var rect = graphic.rectTransform.rect;
            float radius = radiusValue;


            delta_vec_w = outBound.z - outBound.x;
            delta_vec_h = outBound.w - outBound.y;
            delta_uv_w = outUV.z - outUV.x;
            delta_uv_h = outUV.w - outUV.y;


            bound4[0] = new Vector2(rect.position.x, rect.position.y);
            bound4[1] = new Vector2(rect.position.x, rect.position.y + rect.size.y);
            bound4[2] = new Vector2(rect.position.x + rect.size.x, rect.position.y + rect.size.y);
            bound4[3] = new Vector2(rect.position.x + rect.size.x, rect.position.y);



            Vector2[] center4 = new Vector2[4];
            switch (_direction)
            {
                case ERoundCornerDirection.Inner:
                    center4 = bound4;
                    break;
                case ERoundCornerDirection.Outer:
                    center4[0] = new Vector2(bound4[0].x + radius, bound4[0].y + radius); //A
                    center4[1] = new Vector2(bound4[1].x + radius, bound4[1].y - radius); //B
                    center4[2] = new Vector2(bound4[2].x - radius, bound4[2].y - radius); //C
                    center4[3] = new Vector2(bound4[3].x - radius, bound4[3].y + radius); //D
                    break;
            }


            int vertexs = 0;
            float angle = Mathf.PI / 2 / segmentValue;
            angle = _direction == ERoundCornerDirection.Inner ? (angle * -1) : angle;
            float deltaAngle = 0;
            for (int i = 0, length = center4.Length; i < length; i++)
            {
                deltaAngle = DeltaAngleEquation(i);

                var vertex = center4[i];
                var bound = bound4[i];
                int vertexCount = segmentValue + 1;

                int currentCorner = 1 << i;
                bool rightCorner = (cornerTag & currentCorner) != currentCorner;

                if (rightCorner)
                    vertexCount = 1;

                for (int j = 0; j < vertexCount; j++)
                {
                    UIVertex point = GetVertex(vertex, bound, radius, rightCorner, deltaAngle);

                    RefreshVertex(ref point, ref outBound, ref outUV, ref outColor);

                    deltaAngle -= angle;
                    toFill.AddVert(point);
                    vertexs++;
                }
            }

            UIVertex centerVertex = UIVertex.simpleVert;
            centerVertex.position.x = rect.x + rect.width / 2;
            centerVertex.position.y = rect.y + rect.height / 2;

            RefreshVertex(ref centerVertex, ref outBound, ref outUV, ref outColor);

            toFill.AddVert(centerVertex);
            vertexs++;

            for (int i = 0, length = vertexs - 1; i < length; i++)
            {
                toFill.AddTriangle(i, (i + 1) % length, length);
            }
        }

        UIVertex GetVertex(Vector2 center, Vector2 bound, float radius, bool isRight, float angle)
        {
            UIVertex point = UIVertex.simpleVert;

            if (isRight)
            {
                point.position.x = bound.x;
                point.position.y = bound.y;
            }
            else
            {
                point.position.x = center.x + radius * Mathf.Cos(angle);
                point.position.y = center.y + radius * Mathf.Sin(angle);
            }
            return point;
        }

        void RefreshVertex(ref UIVertex vertex, ref Vector4 bound, ref Vector4 outerUv, ref Color color)
        {
            if (vertex.position.y > bound.w)
            {
                vertex.position.y = bound.w;
            }

            if (vertex.position.y < bound.y)
            {
                vertex.position.y = bound.y;
            }

            if (vertex.position.x < bound.x)
            {
                vertex.position.x = bound.x;
            }

            if (vertex.position.x > bound.z)
            {
                vertex.position.x = bound.z;
            }


            float tex_x = (vertex.position.x - bound.x) / delta_vec_w;
            float tex_y = (vertex.position.y - bound.y) / delta_vec_h;

            vertex.uv0.x = tex_x * delta_uv_w + outerUv.x;
            vertex.uv0.y = tex_y * delta_uv_h + outerUv.y;

            vertex.color = color;
        }

        enum ERoundCornerDirection
        {
            Outer,
            Inner
        }



#if UNITY_EDITOR
        protected override void OnValidate()
        {
            base.OnValidate();

            if (!Application.isPlaying)
                SetVertexDirty();
        }

        protected override void Reset()
        {
            base.Reset();

            radiusValue = 20;
            segmentValue = 20;
        }

        public new void OnDestroy()
        {
            base.OnDestroy();

            if (!Application.isPlaying)
            {
                SetVertexDirty();
            }
        }
#endif
    }
}

